/******************************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Ltd.                       */
/*                                                                            */
/*  NAME      = zookeeper_common.c                                            */
/*  NOTE      = TDS 请求解析                                                  */
/*  DATE      = 2015/08/26 by zhengxd                                         */
/******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <stdint.h>
#include <limits.h>

#include "zookeeper_common.h"

#define ZOOKEEPER_KEY_REQ          APM_REPORT_KEY_REQ".zookeeper"
#define ZOOKEEPER_KEY_REQ_TYPE     ZOOKEEPER_KEY_REQ".type"

enum ZOO_ERRORS {
    ZOK = 0, /*!< Everything is OK */

    /** System and server-side errors.
    * This is never thrown by the server, it shouldn't be used other than
    * to indicate a range. Specifically error codes greater than this
    * value, but lesser than {@link #ZAPIERROR}, are system errors. */
    ZSYSTEMERROR = -1,
    ZRUNTIMEINCONSISTENCY = -2, /*!< A runtime inconsistency was found */
    ZDATAINCONSISTENCY = -3, /*!< A data inconsistency was found */
    ZCONNECTIONLOSS = -4, /*!< Connection to the server has been lost */
    ZMARSHALLINGERROR = -5, /*!< Error while marshalling or unmarshalling data */
    ZUNIMPLEMENTED = -6, /*!< Operation is unimplemented */
    ZOPERATIONTIMEOUT = -7, /*!< Operation timeout */
    ZBADARGUMENTS = -8, /*!< Invalid arguments */
    ZINVALIDSTATE = -9, /*!< Invliad zhandle state */

    /** API errors.
    * This is never thrown by the server, it shouldn't be used other than
    * to indicate a range. Specifically error codes greater than this
    * value are API errors (while values less than this indicate a
    * {@link #ZSYSTEMERROR}).
    */
    ZAPIERROR = -100,
    ZNONODE = -101, /*!< Node does not exist */
    ZNOAUTH = -102, /*!< Not authenticated */
    ZBADVERSION = -103, /*!< Version conflict */
    ZNOCHILDRENFOREPHEMERALS = -108, /*!< Ephemeral nodes may not have children */
    ZNODEEXISTS = -110, /*!< The node already exists */
    ZNOTEMPTY = -111, /*!< The node has children */
    ZSESSIONEXPIRED = -112, /*!< The session has been expired by the server */
    ZINVALIDCALLBACK = -113, /*!< Invalid callback specified */
    ZINVALIDACL = -114, /*!< Invalid ACL specified */
    ZAUTHFAILED = -115, /*!< Client authentication failed */
    ZCLOSING = -116, /*!< ZooKeeper is closing */
    ZNOTHING = -117, /*!< (not error) no server responses to process */
    ZSESSIONMOVED = -118 /*!<session moved to another server, so operation is ignored */
};

/*******************************************************************************
*  FUNC     :  释放内存
*  ARGS     :  pp_buffer
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void zookeeper_free(char **pp_buffer)
{
    if (pp_buffer == NULL || *pp_buffer == NULL)
    {
        return;
    }

    frfree(*pp_buffer);
    *pp_buffer = NULL;
    return;
}

/*******************************************************************************
*  FUNC     :  取得时间差(微秒)
*  ARGS     :  st_start_time(开始时间)
*           :  p_st_end_time(结束时间)
*  RTN      :  long
*  NOTE     :
*******************************************************************************/
unsigned long zookeeper_get_interval_time(struct timeval *p_st_start_time
                                            , struct timeval *p_st_end_time)
{
    unsigned long ul_time_interval = 0;
    int i_flg = 0;

    if (p_st_start_time->tv_usec < p_st_end_time->tv_usec)
    {
        ul_time_interval = p_st_end_time->tv_usec - p_st_start_time->tv_usec;
    }
    else
    {
        ul_time_interval = 1000000 + p_st_end_time->tv_usec - p_st_start_time->tv_usec;
        i_flg = 1;
    }

    if (p_st_start_time->tv_sec + i_flg > p_st_end_time->tv_sec)
    {
        ul_time_interval = 0;
    }
    else
    {
        ul_time_interval += 1000000 * (p_st_end_time->tv_sec - p_st_start_time->tv_sec - i_flg);
    }

    return ul_time_interval;
}

/*******************************************************************************
*  FUNC     :  取得string
*  ARGS     :  p_st_data(bytebuff信息)
*           :  p_key (key)
*           :  p_lst_head (list)
*  RTN      :  APM_L7_ANALYZE_SUCC  (success)
*              APM_L7_ANALYZE_FAIL  (failed)
*  NOTE     :
*******************************************************************************/
int zookeeper_get_string(Frbyte_Packet *p_st_data
                        , const char *p_key
                        , Frlist_header *p_lst_head)
{
    int i_ret = FR_SUCC;
    uint32_t u32_len = 0;
    char *p_value = NULL;
    int i_remaining_len = 0;
    Frvar_field *p_st_field = NULL;
    Frlist_node *p_st_node = NULL;

    /* 取得长度 */
    i_ret = bytebuff_get_int(p_st_data, 4, &u32_len, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        return APM_L7_ANALYZE_FAIL;
    }
    /* 0xffffffff时内容为NULL */
    if (u32_len == 0xffffffff)
    {
        return APM_L7_ANALYZE_SUCC;
    }

    /* 长度不足 */
    i_remaining_len = bytebuff_remaining(p_st_data);
    if (u32_len > (uint32_t)i_remaining_len)
    {
        return APM_L7_ANALYZE_FAIL;
    }

    /* 生成str内存 */
    p_value = (char *)frmalloc(u32_len + 1);
    if (p_value == NULL)
    {
        return APM_L7_ANALYZE_FAIL;
    }
    /* 取得string */
    i_ret = bytebuff_get_bytes(p_st_data, p_value, u32_len);
    if (i_ret != FR_SUCC)
    {
        frfree(p_value);
        return APM_L7_ANALYZE_FAIL;
    }
    p_value[u32_len] = '\0';

    /* 创建field */
    p_st_field = (Frvar_field *)frmalloc(sizeof(Frvar_field));
    if(p_st_field == NULL)
    {
        frfree(p_value);
        return APM_L7_ANALYZE_FAIL;
    }
    memset(p_st_field, 0x00, sizeof(Frvar_field));
    p_st_field->p_field_name = frstrdup(p_key);
    p_st_field->em_data_type = FRSTRING;
    p_st_field->field_value.p_value = p_value;

    /* 创建节点 */
    p_st_node = frlist_node_create(p_st_field);
    if (p_st_node == NULL)
    {
        frvarfield_free(&p_st_field);
        return APM_L7_ANALYZE_FAIL;
    }
    /* 追加节点 */
    frlist_push(p_lst_head, p_st_node);
    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  跳过string
*  ARGS     :  p_st_data(bytebuff信息)
*  RTN      :  APM_L7_ANALYZE_SUCC  (success)
*           :  APM_L7_ANALYZE_FAIL  (FAIL)
*  NOTE     :
*******************************************************************************/
int zookeeper_skip_string(Frbyte_Packet *p_st_data)
{
    int i_ret = FR_SUCC;
    uint32_t u32_len = 0;
    int i_remaining_len = 0;

    /* 取得长度 */
    i_ret = bytebuff_get_int(p_st_data, 4, &u32_len, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        return APM_L7_ANALYZE_FAIL;
    }
    /* 0xffffffff时内容为NULL */
    if (u32_len == 0xffffffff)
    {
        return APM_L7_ANALYZE_SUCC;
    }

    /* 长度不足 */
    i_remaining_len = bytebuff_remaining(p_st_data);
    if (u32_len > (uint32_t)i_remaining_len)
    {
        return APM_L7_ANALYZE_FAIL;
    }
    bytebuff_skip(p_st_data, u32_len);

    return APM_L7_ANALYZE_SUCC;
}
/*******************************************************************************
*  FUNC     :  取得buffer
*  ARGS     :  p_st_data(bytebuff信息)
*           :  p_key (key)
*           :  p_lst_head (list)
*  RTN      :  APM_L7_ANALYZE_SUCC  (success)
*              APM_L7_ANALYZE_FAIL  (failed)
*  NOTE     :
*******************************************************************************/
int zookeeper_get_buffer(Frbyte_Packet *p_st_data
                        , const char *p_key
                        , Frlist_header *p_lst_head)
{
    int i_ret = FR_SUCC;
    uint32_t u32_len = 0;
    char *p_value = NULL;
    int i_remaining_len = 0;
    Frbindata *p_st_value = NULL;
    Frvar_field *p_st_field = NULL;
    Frlist_node *p_st_node = NULL;

    /* 取得长度 */
    i_ret = bytebuff_get_int(p_st_data, 4, &u32_len, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        return APM_L7_ANALYZE_FAIL;
    }
    /* 0xffffffff时内容为NULL */
    if (u32_len == 0xffffffff)
    {
        return APM_L7_ANALYZE_SUCC;
    }

    /* 长度不足 */
    i_remaining_len = bytebuff_remaining(p_st_data);
    if (u32_len > (uint32_t)i_remaining_len)
    {
        return APM_L7_ANALYZE_FAIL;
    }

    /* 生成str内存 */
    p_value = (char *)frmalloc(u32_len + 1);
    if (p_value == NULL)
    {
        return APM_L7_ANALYZE_FAIL;
    }
    /* 取得string */
    i_ret = bytebuff_get_bytes(p_st_data, p_value, u32_len);
    if (i_ret != FR_SUCC)
    {
        frfree(p_value);
        return APM_L7_ANALYZE_FAIL;
    }
    p_value[u32_len] = '\0';

    /* 创建Frbindata */
    p_st_value = (Frbindata *)frmalloc(sizeof(Frbindata));
    if(p_st_value == NULL)
    {
        frfree(p_value);
        return APM_L7_ANALYZE_FAIL;
    }
    memset(p_st_value, 0x00, sizeof(Frbindata));
    p_st_value->ui_len = u32_len;
    p_st_value->p_data = p_value;

    /* 创建field */
    p_st_field = (Frvar_field *)frmalloc(sizeof(Frvar_field));
    if(p_st_field == NULL)
    {
        frfree(p_value);
        frfree(p_st_value);
        return APM_L7_ANALYZE_FAIL;
    }
    memset(p_st_field, 0x00, sizeof(Frvar_field));
    p_st_field->p_field_name = frstrdup(p_key);
    p_st_field->em_data_type = FRCLOB;
    p_st_field->field_value.p_st_value = p_st_value;

    /* 创建节点 */
    p_st_node = frlist_node_create(p_st_field);
    if (p_st_node == NULL)
    {
        frvarfield_free(&p_st_field);
        return APM_L7_ANALYZE_FAIL;
    }
    /* 追加节点 */
    frlist_push(p_lst_head, p_st_node);
    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  跳过buffer
*  ARGS     :  p_st_data(bytebuff信息)
*  RTN      :  APM_L7_ANALYZE_SUCC  (success)
*           :  APM_L7_ANALYZE_FAIL  (fail)
*  NOTE     :
*******************************************************************************/
int zookeeper_skip_buffer(Frbyte_Packet *p_st_data)
{
    return zookeeper_skip_string(p_st_data);
}

/*******************************************************************************
*  FUNC     :  跳过acl
*  ARGS     :  p_st_data(bytebuff信息)
*  RTN      :  APM_L7_ANALYZE_SUCC  (success)
*           :  APM_L7_ANALYZE_FAIL  (fail)
*  NOTE     :
*******************************************************************************/
int zookeeper_skip_id(Frbyte_Packet *p_st_data)
{
    int i_ret = APM_L7_ANALYZE_SUCC;

    /* 根据源码ID = scheme(string) + id(string) */
    /* scheme */
    i_ret = zookeeper_skip_string(p_st_data);
    if (i_ret == APM_L7_ANALYZE_FAIL)
    {
        return i_ret;
    }
    /* id */
    return zookeeper_skip_string(p_st_data);
}

/*******************************************************************************
*  FUNC     :  跳过acl
*  ARGS     :  p_st_data(bytebuff信息)
*  RTN      :  APM_L7_ANALYZE_SUCC  (success)
*           :  APM_L7_ANALYZE_FAIL  (fail)
*  NOTE     :
*******************************************************************************/
int zookeeper_skip_acl(Frbyte_Packet *p_st_data)
{
    int i_ret = APM_L7_ANALYZE_SUCC;

    /* 根据源码ID = perms(int) + ID(id) */
    /* perms */
    i_ret = bytebuff_skip(p_st_data ,ZOOKEEPER_INT_LEN);
    if (i_ret != FR_SUCC)
    {
        return APM_L7_ANALYZE_FAIL;
    }
    /* id */
    return zookeeper_skip_id(p_st_data);
}

/*******************************************************************************
*  FUNC     :  跳过acl组
*  ARGS     :  p_st_data(bytebuff信息)
*  RTN      :  APM_L7_ANALYZE_SUCC  (success)
*           :  APM_L7_ANALYZE_FAIL  (fail)
*  NOTE     :
*******************************************************************************/
int zookeeper_skip_acl_vector(Frbyte_Packet *p_st_data)
{
    int i_ret = FR_SUCC;
    uint32_t u32_vector = 0;

    /* 取得个数 */
    i_ret = bytebuff_get_int(p_st_data, 4, &u32_vector, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        return APM_L7_ANALYZE_FAIL;
    }

    while (u32_vector--)
    {
        i_ret = zookeeper_skip_acl(p_st_data);
        if (i_ret == APM_L7_ANALYZE_FAIL)
        {
            return i_ret;
        }
    }

    return APM_L7_ANALYZE_SUCC;
}


/*******************************************************************************
*  FUNC     :  取得String vector
*  ARGS     :  p_st_data(bytebuff信息)
*           :  p_key (key)
*           :  p_lst_head (list)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
int zookeeper_get_str_vector(Frbyte_Packet *p_st_data
                             , const char *p_key
                             , Frlist_header *p_lst_head)
{
    int i_ret = FR_SUCC;
    unsigned int ui_loop = 0;
    uint32_t u32_vector = 0;
    char arr_key[64] = {0};
    snprintf(arr_key, sizeof(arr_key), "%s", p_key);
    char *p_tmp = arr_key;
    unsigned int ui_len_tmp = strlen(p_tmp);
    p_tmp += ui_len_tmp;

    /* 取得个数 */
    i_ret = bytebuff_get_int(p_st_data, 4, &u32_vector, BYTE_BIG_ENDIAN);
    if (i_ret != FR_SUCC)
    {
        return APM_L7_ANALYZE_FAIL;
    }

    while (u32_vector--)
    {
        snprintf(p_tmp, sizeof(arr_key) - ui_len_tmp, ".data.%d", ++ui_loop);
        i_ret = zookeeper_get_string(p_st_data, arr_key, p_lst_head);
        if (i_ret == APM_L7_ANALYZE_FAIL)
        {
            return i_ret;
        }
    }

    return APM_L7_ANALYZE_SUCC;
}

/*******************************************************************************
*  FUNC     :  初始化分片包信息
*  ARGS     :  p_st_fragment(分片包信息)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void zookeeper_init_fragment(L7_fragment_zookeeper *p_st_fragment)
{
    if (p_st_fragment)
    {
        bytebuff_free(&p_st_fragment->p_st_data);
        memset(p_st_fragment, 0x0, sizeof(L7_fragment_zookeeper));
    }
    return;
}

/*******************************************************************************
*  FUNC     :  销毁分片包信息
*  ARGS     :  pp_st_fragment(分片包信息)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void zookeeper_destroy_fragment(L7_fragment_zookeeper **pp_st_fragment)
{
    if (pp_st_fragment == NULL || *pp_st_fragment == NULL)
    {
        return;
    }
    L7_fragment_zookeeper *p_st_fragment = *pp_st_fragment;

    bytebuff_free(&p_st_fragment->p_st_data);
    frfree(p_st_fragment);
    *pp_st_fragment = NULL;
    return;
}

/*******************************************************************************
*  FUNC     :  销毁session
*  ARGS     :  pp_st_sess(session信息)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void zookeeper_destroy_session(L7session_zookeeper **pp_st_sess)
{
    if (pp_st_sess == NULL || *pp_st_sess == NULL)
    {
        return;
    }
    L7session_zookeeper *p_st_sess = *pp_st_sess;

    frfree(p_st_sess);
    *pp_st_sess = NULL;
    return;
}

/*******************************************************************************
*  FUNC     :  body里的node节点内存释放
*  ARGS     :  p_st_node  (Frlist_node *)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void frbindata_node_free(Frlist_node *node)
{
    if(node == NULL || node->data==NULL)
        return;

    Frvar_field *p_st_field = (Frvar_field *)node->data;
    if(p_st_field)
        frvarfield_free(&p_st_field);
    if(p_st_field)
        frfree(p_st_field);
    return;
}

/*******************************************************************************
*  FUNC     :  请求节点信息销毁
*  ARGS     :  p_st_node(请求节点)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void zookeeper_req_node_free(Frlist_node *p_st_node)
{
    if (p_st_node == NULL || p_st_node->data == NULL)
    {
        return;
    }

    L7_req_zookeeper *p_st_req = (L7_req_zookeeper *)p_st_node->data;
    /* 释放数据 */
    frlist_remove_all(&p_st_req->st_data_lst, frbindata_node_free);
    frfree(p_st_req);

    return;
}

/*******************************************************************************
*  FUNC     :  销毁请求信息
*  ARGS     :  pp_st_sess(请求信息)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void zookeeper_destroy_req(L7_req_zookeeper **pp_st_req)
{
    if (pp_st_req == NULL || *pp_st_req == NULL)
    {
        return;
    }
    L7_req_zookeeper *p_st_req = *pp_st_req;

    frlist_remove_all(&p_st_req->st_data_lst, frbindata_node_free);
    frfree(p_st_req);
    *pp_st_req = NULL;
    return;
}

/*******************************************************************************
*  FUNC     :  销毁响应
*  ARGS     :  pp_st_sess(响应信息)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void zookeeper_destroy_resp(L7_resp_zookeeper **pp_st_resp)
{
    if (pp_st_resp == NULL || *pp_st_resp == NULL)
    {
        return;
    }
    L7_resp_zookeeper *p_st_resp = *pp_st_resp;

    frfree(p_st_resp);
    *pp_st_resp = NULL;
    return;
}

/*******************************************************************************
*  FUNC     :  初始化本次请求响应信息
*  ARGS     :  p_st_private(本次请求响应信息)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void zookeeper_init_curr_info(L7session_zookeeper_private *p_st_private)
{
    zookeeper_init_fragment(p_st_private->p_st_fragment);
    zookeeper_destroy_resp(&p_st_private->p_st_resp);
    return;
}

/*******************************************************************************
*  FUNC     :  上报请求/响应信息
*  ARGS     :  p_st_conn(ct信息)
*  ARGS     :  p_st_private(私有信息)
*  ARGS     :  p_st_hash_report(保存Frreport_data)
*  ARGS     :  i_resp_flg(是否需要上报response)
*  RTN      :
*  NOTE     :
*******************************************************************************/
int zookeeper_report_data(Conntrack *p_st_conn
                          , L7session_zookeeper_private *p_st_private
                          , L7_req_zookeeper *p_st_req
                          , Frhash_header *p_st_hash_report
                          , int i_resp_flg)
{
    int i_ret = FR_SUCC;
    unsigned long ul_server_time_us = 0;
    unsigned long ul_download_time_us = 0;
    Frreport_data *p_st_report_data = NULL;
    Frreport_body_data *p_st_sess_body = NULL;
    L7_resp_zookeeper *p_st_resp = p_st_private->p_st_resp;
    L7_fragment_zookeeper *p_st_fragment = p_st_private->p_st_fragment;
    char arr_key[128] = {0};
    snprintf(arr_key, sizeof(arr_key), "%s", ZOOKEEPER_KEY_REQ);
    char *p_key = arr_key;
    unsigned int ui_key_len = strlen(p_key);
    p_key += ui_key_len;
    ui_key_len = sizeof(arr_key) - ui_key_len;
    Frlist_node *p_st_node = NULL;
    Frvar_field *p_st_field = NULL;
    char arr_title[32] = {0};

    switch (p_st_req->i_req_type)
    {
        case ZOOKEEPER_CLOSE_OP:
            snprintf(arr_title, 32, "CLOSE");
            break;

        case ZOOKEEPER_CREATE_OP:
            snprintf(arr_title, 32, "CREATE");
            break;

        case ZOOKEEPER_DELETE_OP:
            snprintf(arr_title, 32, "DELETE");
            break;

        case ZOOKEEPER_EXISTS_OP:
            snprintf(arr_title, 32, "EXISTS");
            break;

        case ZOOKEEPER_GETDATA_OP:
            snprintf(arr_title, 32, "GETDATA");
            break;

        case ZOOKEEPER_SETDATA_OP:
            snprintf(arr_title, 32, "SETDATA");
            break;

        case ZOOKEEPER_GETACL_OP:
            snprintf(arr_title, 32, "GETACL");
            break;

        case ZOOKEEPER_SETACL_OP:
            snprintf(arr_title, 32, "SETACL");
            break;

        case ZOOKEEPER_GETCHILDREN_OP:
            snprintf(arr_title, 32, "GETCHILDREN");
            break;

        case ZOOKEEPER_SYNC_OP:
            snprintf(arr_title, 32, "SYNC");
            break;

        case ZOOKEEPER_GETCHILDREN2_OP:
            snprintf(arr_title, 32, "GETCHILDREN2");
            break;

        case ZOOKEEPER_CHECK_OP:
            snprintf(arr_title, 32, "CHECK");
            break;

        case ZOOKEEPER_MULTI_OP:
            snprintf(arr_title, 32, "MULTI");
            break;

        /* ping 包不上报 */
        case ZOOKEEPER_PING_OP:
            //snprintf(arr_title, 32, "PING");
            //break;
            return APM_L7_ANALYZE_SUCC;

         /* connect不上报,只设置login */
        case ZOOKEEPER_CONNECT_OP:
            if (i_resp_flg == FR_YES)
            {
                p_st_private->p_st_sess->st_conn =p_st_fragment->st_end_timestamp;
            }
            return APM_L7_ANALYZE_SUCC;

        case ZOOKEEPER_SETWATCHES_OP:
            snprintf(arr_title, 32, "SETWATCHES");
            break;

        case ZOOKEEPER_SETAUTH_OP:
            snprintf(arr_title, 32, "SETAUTH");
            break;

        default:
            return APM_L7_ANALYZE_FAIL;
    }

    /* 创建report body */
    p_st_sess_body = frreport_body_new_l7(p_st_conn);
    if (p_st_sess_body == NULL)
    {
        return APM_L7_ANALYZE_FAIL;
    }
    /* 追加connection相关信息 */
    i_ret = frreport_body_l7_add_connInfo(p_st_sess_body, p_st_conn);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }

    /* add login time */
    if (p_st_private->p_st_sess->st_conn.tv_sec != 0
        || p_st_private->p_st_sess->st_conn.tv_usec != 0)
    {
        /* add request start time */
        i_ret = frreport_body_l7_add_timeval(p_st_sess_body
                                            , APM_REPORT_KEY_SESSION_LOGIN_TIMESTAMP
                                            , &p_st_private->p_st_sess->st_conn);
        if (i_ret != FR_SUCC)
        {
            frreport_body_free(&p_st_sess_body);
            return APM_L7_ANALYZE_FAIL;
        }
    }

    /* add sequence id */
    i_ret = frreport_body_l7_add_ulong(p_st_sess_body
                                      , APM_REPORT_KEY_REQ_ID
                                      , p_st_req->ul_req_sequence);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }

    /* add isResponseRequired */
    i_ret = frreport_body_l7_add_int(p_st_sess_body
                                    , APM_REPORT_KEY_REQ_ISRESPREQUIRED, 1);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }
    /* add request start time */
    i_ret = frreport_body_l7_add_timeval(p_st_sess_body
                                        , APM_REPORT_KEY_REQ_START_TIMESTAMP
                                        , &p_st_req->st_start_timestamp);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }
    /* add request end time */
    i_ret = frreport_body_l7_add_timeval(p_st_sess_body
                                        , APM_REPORT_KEY_REQ_END_TIMESTAMP
                                        , &p_st_req->st_end_timestamp);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }

    /* add send time */
    i_ret = frreport_body_l7_add_ulong(p_st_sess_body
                                      , APM_REPORT_KEY_REQ_SEND_TIME_US
                                      , p_st_req->ul_send_time_us);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }
    /* add send data bytes */
    i_ret = frreport_body_l7_add_ulong(p_st_sess_body
                                      , APM_REPORT_KEY_REQ_DATA_BYTES
                                      , p_st_req->ui_total_len);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }

    /* add title */
    i_ret = frreport_body_l7_add_str(p_st_sess_body
                                     , APM_REPORT_KEY_TRANS_TITLE
                                     , arr_title);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }

    /* add type */
    i_ret = frreport_body_l7_add_str(p_st_sess_body
                                     , ZOOKEEPER_KEY_REQ_TYPE
                                     , arr_title);
    if (i_ret != FR_SUCC)
    {
        frreport_body_free(&p_st_sess_body);
        return APM_L7_ANALYZE_FAIL;
    }

    p_st_node = FRLIST_FIRST_NODE(&p_st_req->st_data_lst);
    while (p_st_node)
    {
        p_st_field = (Frvar_field *)FRLIST_GET_NODE_DATA(p_st_node);
        switch (p_st_field->em_data_type)
        {
            case FRSTRING:
                snprintf(p_key, ui_key_len, ".%s", p_st_field->p_field_name);
                i_ret = frreport_body_l7_add_str(p_st_sess_body, arr_key
                                                , p_st_field->field_value.p_value ? p_st_field->field_value.p_value: "");
                break;

            case FRCLOB:
                snprintf(p_key, ui_key_len, ".%s", p_st_field->p_field_name);
                i_ret = frreport_body_l7_add_bin(p_st_sess_body, arr_key
                                                 , p_st_field->field_value.p_st_value->p_data
                                                 , p_st_field->field_value.p_st_value->ui_len);
                break;

            default:
                i_ret = FR_FAIL;
            break;
        }
        if (i_ret != FR_SUCC)
        {
            frreport_body_free(&p_st_sess_body);
            return APM_L7_ANALYZE_FAIL;
        }
        p_st_node = FRLIST_NEXT_NODE(p_st_node);
    }

    if (i_resp_flg == FR_YES)
    {
        /* add response start time */
        i_ret = frreport_body_l7_add_timeval(p_st_sess_body
                                            , APM_REPORT_KEY_RESP_START_TIMESTAMP
                                            , &p_st_fragment->st_start_timestamp);
        if (i_ret != FR_SUCC)
        {
            frreport_body_free(&p_st_sess_body);
            return APM_L7_ANALYZE_FAIL;
        }
        /* add response end time */
        i_ret = frreport_body_l7_add_timeval(p_st_sess_body
                                            , APM_REPORT_KEY_RESP_END_TIMESTAMP
                                            , &p_st_fragment->st_end_timestamp);
        if (i_ret != FR_SUCC)
        {
            frreport_body_free(&p_st_sess_body);
            return APM_L7_ANALYZE_FAIL;
        }

        ul_server_time_us = zookeeper_get_interval_time(&p_st_req->st_end_timestamp
                                                       , &p_st_fragment->st_start_timestamp);
        /* add response response_time_us */
        i_ret = frreport_body_l7_add_ulong(p_st_sess_body
                                          , APM_REPORT_KEY_RESP_SERVER_TIME_US
                                          , ul_server_time_us);
        if (i_ret != FR_SUCC)
        {
            frreport_body_free(&p_st_sess_body);
            return APM_L7_ANALYZE_FAIL;
        }

        ul_download_time_us = zookeeper_get_interval_time(&p_st_fragment->st_start_timestamp
                                                         , &p_st_fragment->st_end_timestamp);
        /* add response response_time_us */
        i_ret = frreport_body_l7_add_ulong(p_st_sess_body
                                          , APM_REPORT_KEY_RESP_DOWNLOAD_TIME_US
                                          , ul_download_time_us);
        if (i_ret != FR_SUCC)
        {
            frreport_body_free(&p_st_sess_body);
            return APM_L7_ANALYZE_FAIL;
        }

        /* add response response bytes */
        i_ret = frreport_body_l7_add_ulong(p_st_sess_body
                                          , APM_REPORT_KEY_RESP_DATA_BYTES
                                          , p_st_fragment->ui_total_len);
        if (i_ret != FR_SUCC)
        {
            frreport_body_free(&p_st_sess_body);
            return APM_L7_ANALYZE_FAIL;
        }

        /* add response response code */
        if(frreport_body_l7_add_int(p_st_sess_body, APM_REPORT_KEY_RESP_CODE, p_st_resp->i_error_num) == FR_FAIL)
        {
            frreport_body_free(&p_st_sess_body);
            return APM_L7_ANALYZE_FAIL;
        }
        //add response message
        switch (p_st_resp->i_error_num)
        {
            case ZOK:
                i_ret = frreport_body_l7_add_str(p_st_sess_body
                                                 , APM_REPORT_KEY_RESP_ERR_MSG
                                                 , "ok");
                break;

            case ZSYSTEMERROR:
                i_ret = frreport_body_l7_add_str(p_st_sess_body
                                                 , APM_REPORT_KEY_RESP_ERR_MSG
                                                 , "system error");
                break;

            case ZRUNTIMEINCONSISTENCY:
                i_ret = frreport_body_l7_add_str(p_st_sess_body
                                                 , APM_REPORT_KEY_RESP_ERR_MSG
                                                 , "run time inconsistency");
                break;

            case ZDATAINCONSISTENCY:
                i_ret = frreport_body_l7_add_str(p_st_sess_body
                                                 , APM_REPORT_KEY_RESP_ERR_MSG
                                                 , "data inconsistency");
                break;

            case ZCONNECTIONLOSS:
                i_ret = frreport_body_l7_add_str(p_st_sess_body
                                                 , APM_REPORT_KEY_RESP_ERR_MSG
                                                 , "connection loss");
                break;

            case ZMARSHALLINGERROR:
                i_ret = frreport_body_l7_add_str(p_st_sess_body
                                                 , APM_REPORT_KEY_RESP_ERR_MSG
                                                 , "marshalling error");
                break;

            case ZUNIMPLEMENTED:
                i_ret = frreport_body_l7_add_str(p_st_sess_body
                                                 , APM_REPORT_KEY_RESP_ERR_MSG
                                                 , "unimplemented");
                break;

            case ZOPERATIONTIMEOUT:
                i_ret = frreport_body_l7_add_str(p_st_sess_body
                                                , APM_REPORT_KEY_RESP_ERR_MSG
                                                , "operation timeout");
                break;

            case ZBADARGUMENTS:
                i_ret = frreport_body_l7_add_str(p_st_sess_body
                                                , APM_REPORT_KEY_RESP_ERR_MSG
                                                , "bad arguments");
                break;

            case ZINVALIDSTATE:
                i_ret = frreport_body_l7_add_str(p_st_sess_body
                                                , APM_REPORT_KEY_RESP_ERR_MSG
                                                , "invalid zhandle state");
                break;

            case ZAPIERROR:
                i_ret = frreport_body_l7_add_str(p_st_sess_body
                                                 , APM_REPORT_KEY_RESP_ERR_MSG
                                                 , "api error");
                break;

            case ZNONODE:
                i_ret = frreport_body_l7_add_str(p_st_sess_body
                                                , APM_REPORT_KEY_RESP_ERR_MSG
                                                , "no node");
                break;

            case ZNOAUTH:
                i_ret = frreport_body_l7_add_str(p_st_sess_body
                                                , APM_REPORT_KEY_RESP_ERR_MSG
                                                , "not authenticated");
                break;

            case ZBADVERSION:
                i_ret = frreport_body_l7_add_str(p_st_sess_body
                                                 , APM_REPORT_KEY_RESP_ERR_MSG
                                                 , "bad version");
                break;

            case  ZNOCHILDRENFOREPHEMERALS:
                i_ret = frreport_body_l7_add_str(p_st_sess_body
                                                 , APM_REPORT_KEY_RESP_ERR_MSG
                                                 , "no children for ephemerals");
                break;

            case ZNODEEXISTS:
                i_ret = frreport_body_l7_add_str(p_st_sess_body
                                                 , APM_REPORT_KEY_RESP_ERR_MSG
                                                 , "node exists");
                break;

            case ZNOTEMPTY:
                i_ret = frreport_body_l7_add_str(p_st_sess_body
                                                 , APM_REPORT_KEY_RESP_ERR_MSG
                                                 , "not empty");
                break;

            case ZSESSIONEXPIRED:
                i_ret = frreport_body_l7_add_str(p_st_sess_body
                                                 , APM_REPORT_KEY_RESP_ERR_MSG
                                                 , "session expired");
                break;

            case ZINVALIDCALLBACK:
                i_ret = frreport_body_l7_add_str(p_st_sess_body
                                                 , APM_REPORT_KEY_RESP_ERR_MSG
                                                 , "invalid callback");
                break;

            case ZINVALIDACL:
                i_ret = frreport_body_l7_add_str(p_st_sess_body
                                                 , APM_REPORT_KEY_RESP_ERR_MSG
                                                 , "invalid acl");
                break;

            case ZAUTHFAILED:
                i_ret = frreport_body_l7_add_str(p_st_sess_body
                                                 , APM_REPORT_KEY_RESP_ERR_MSG
                                                 , "authentication failed");
                break;

            case ZCLOSING:
                i_ret = frreport_body_l7_add_str(p_st_sess_body
                                                 , APM_REPORT_KEY_RESP_ERR_MSG
                                                 , "zookeeper is closing");
                break;

            case ZNOTHING:
                i_ret = frreport_body_l7_add_str(p_st_sess_body
                                                 , APM_REPORT_KEY_RESP_ERR_MSG
                                                 , "(not error) no server responses to process");
                break;

            case ZSESSIONMOVED:
                i_ret = frreport_body_l7_add_str(p_st_sess_body
                                                 , APM_REPORT_KEY_RESP_ERR_MSG
                                                 , "session moved to another server, so operation is ignored");
                break;

            default:
                i_ret = frreport_body_l7_add_str(p_st_sess_body
                                                 , APM_REPORT_KEY_RESP_ERR_MSG
                                                 , "unknown error");
                break;
        }
        if (i_ret != FR_SUCC)
        {
            frreport_body_free(&p_st_sess_body);
            return APM_L7_ANALYZE_FAIL;
        }

        /* 创建report data header */
        p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_RESP);
        if (p_st_report_data == NULL)
        {
            frreport_body_free(&p_st_sess_body);
            return APM_L7_ANALYZE_FAIL;
        }
        /* add body into header */
        i_ret = frreport_data_add_body(p_st_report_data, p_st_sess_body);
        if (i_ret != FR_SUCC)
        {
            frreport_body_free(&p_st_sess_body);
            frreport_data_free(&p_st_report_data);
            return APM_L7_ANALYZE_FAIL;
        }

        /* 上报request数据 */
        i_ret = frreport_data_hash(p_st_hash_report, p_st_report_data);
        if (i_ret != FR_SUCC)
        {
            frreport_data_free(&p_st_report_data);
            return APM_L7_ANALYZE_FAIL;
        }

        return APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
    }
    else
    {
        /* 创建report data header */
        p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_REQ);
        if (p_st_report_data == NULL)
        {
            frreport_body_free(&p_st_sess_body);
            return APM_L7_ANALYZE_FAIL;
        }
        /* add body into header */
        i_ret = frreport_data_add_body(p_st_report_data, p_st_sess_body);
        if (i_ret != FR_SUCC)
        {
            frreport_body_free(&p_st_sess_body);
            frreport_data_free(&p_st_report_data);
            return APM_L7_ANALYZE_FAIL;
        }

        /* 上报request数据 */
        i_ret = frreport_data_hash(p_st_hash_report, p_st_report_data);
        if (i_ret != FR_SUCC)
        {
            frreport_data_free(&p_st_report_data);
            return APM_L7_ANALYZE_FAIL;
        }

        return APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
    }
}
